-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(behaviors): Add behavior metadata information. #2231
feat(behaviors): Add behavior metadata information. #2231
Conversation
petejohanson
commented
Mar 27, 2024
- For upcoming ZMK studio work, make a set of rich metadata available to provide a friendly name for a behavior, and allow super flexible descriptions of the parameters the behaviors take.
55e55a0
to
05cb259
Compare
app/dts/behaviors/to_layer.dtsi
Outdated
@@ -9,6 +9,7 @@ | |||
/omit-if-no-ref/ to: to_layer { | |||
compatible = "zmk,behavior-to-layer"; | |||
#binding-cells = <1>; | |||
friendly-name = "Go To Layer"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't call this "Go To Layer" anywhere in the docs, just "To Layer". I think it'd be good to be consistent, do you prefer the former?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I was reading it.. I realized it was a pretty odd name. I'll update to match our current language.
app/dts/behaviors/toggle_layer.dtsi
Outdated
@@ -9,6 +9,7 @@ | |||
/omit-if-no-ref/ tog: toggle_layer { | |||
compatible = "zmk,behavior-toggle-layer"; | |||
#binding-cells = <1>; | |||
friendly-name = "Layer Toggle"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also typically called "Toggle Layer." Having a proper noun phrase rather than verb+action might be better in general, but I'd again tend to consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll defer to consistency for now, but I do think this reads better than "Toggle Layer", IMHO.
05cb259
to
88042aa
Compare
app/src/behaviors/behavior_bt.c
Outdated
.position = 0, | ||
.value = BT_NXT_CMD, | ||
.friendly_name = "Next Profile", | ||
.type = BEHAVIOR_PARAMETER_VALUE_METADATA_TYPE_VALUE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think it would be easier to read these if the type came before the value/range/etc. Maybe this would be a good order?
- Position
- Name
- Type
- Value/range/etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Definitely reads better, thanks!
e968c3a
to
0119f0b
Compare
fda849e
to
a9d724f
Compare
a9d724f
to
053cf08
Compare
app/include/drivers/behavior.h
Outdated
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_NULL = 0, | ||
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HID_USAGE = 1, | ||
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_LAYER_INDEX = 2, | ||
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HSV = 3, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HSV = 3, | |
BEHAVIOR_PARAMETER_STANDARD_DOMAIN_COLOR_HSV = 3, |
might make it clearer what HSV means. (If it isn't supposed to be a color, then this really needs to be clarified.)
Also, RGB seems like a generally more common format for sending color data. I guess we could add a *_COLOR_RGB value later, but then we'd have to deal with two different color formats everywhere.
One alternative would be to change the underglow code to store the value as RGB, then convert to HSV when loading. If the devicetree format needs to match, we could also change RGB_COLOR_HSB_VAL() to convert from HSV to RGB.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had originally used "HSV" as the "native" format to make it easier to do increase/decrease brightness, IIRC. I don't have a strong opinion here, tbh. Maybe @Nicell has soe thoughts though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main concern is that you can only represent a small fraction of the possible RGB colors using integer HSV values. Assuming I correctly wrote the Python script I used to test this, rgb_underglow.c's hsb_to_rgb()
function can represent 2,189,687 out of 16,777,216 possible colors (about 13%).
29be027
to
cd1c6d0
Compare
e5b4818
to
0598671
Compare
app/include/drivers/behavior.h
Outdated
}; | ||
|
||
enum { | ||
BEHAVIOR_PARAMETER_VALUE_METADATA_TYPE_VALUE = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need "metadata" here? This is the type of the parameter value, not the type of the metadata itself, so this naming could be a little confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shortened.
@@ -209,9 +213,98 @@ static int on_macro_binding_released(struct zmk_behavior_binding *binding, | |||
return ZMK_BEHAVIOR_OPAQUE; | |||
} | |||
|
|||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) | |||
|
|||
static int get_macro_parameter_metadata(const struct device *macro, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is massive. Any way it could be broken into smaller pieces?
The combination of loop conditions with param1_found/param2_found and continue/break statements is particularly difficult to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, cleaned this up a ton, after properly identifying the edges. Read better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might warrant some extra comments explaining exactly what this is doing, but I think I correctly understand what it's doing now, so definitely an improvement.
Just to be sure, this is looping through the list of bindings in the macro, looking for the first thing it can find that uses each of the macro parameters, then returning a combination of the sets for each of those? I'm not sure I understand why the logic for param1 is different than param1 though. Does the param1 case not need to check if the bound param2 is valid?
3a92c3b
to
1057852
Compare
276ad58
to
3949f90
Compare
app/src/behavior.c
Outdated
switch (value_meta->type) { | ||
case BEHAVIOR_PARAMETER_VALUE_TYPE_NIL: | ||
if (param == 0) { | ||
found_match = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we unconditionally break from the loop and return 0 upon reaching any of these found_match = true
cases, maybe we should just return 0 directly instead? Could add something like #define FOUND_MATCH 0
so this becomes return FOUND_MATCH;
and stays clear that we're returning a value that indicates we found a match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, in a split out function. Thanks!
return 0; | ||
} | ||
|
||
int zmk_behavior_validate_param_values(const struct behavior_parameter_value_metadata *values, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the name "validate param values", I first thought this was for validating the struct behavior_parameter_value_metadata
array itself. Not sure how better to clarify this. Could add some documentation to explain it, or maybe rename it? Some ideas
zmk_behavior_matches_param_values()
zmk_behavior_validate_param_with_param_values()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to zmk_behavior_check_params_match_metadata
for clarity. That work for you?
|
||
if (child_meta.sets_len > 0) { | ||
data->set.param1_values = child_meta.sets[0].param1_values; | ||
data->set.param1_values_len = child_meta.sets[0].param1_values_len; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it assumed that these are already zeroed out before calling this function, or is it intentional to leave it at its previous value in the case where the behavior_get_parameter_metadata()
function returns an empty list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the assumption is the set's got a default zero'd state before this gets called.
@@ -209,9 +213,98 @@ static int on_macro_binding_released(struct zmk_behavior_binding *binding, | |||
return ZMK_BEHAVIOR_OPAQUE; | |||
} | |||
|
|||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) | |||
|
|||
static int get_macro_parameter_metadata(const struct device *macro, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might warrant some extra comments explaining exactly what this is doing, but I think I correctly understand what it's doing now, so definitely an improvement.
Just to be sure, this is looping through the list of bindings in the macro, looking for the first thing it can find that uses each of the macro parameters, then returning a combination of the sets for each of those? I'm not sure I understand why the logic for param1 is different than param1 though. Does the param1 case not need to check if the bound param2 is valid?
3949f90
to
afe947b
Compare
* For upcoming ZMK studio work, make a set of rich metadata available to provide a friendly name for a behavior, and allow super flexible descriptions of the parameters the behaviors take. * Add ability to validate a zmk_behavior_binding against the behavior metadata available.
afe947b
to
fc1a281
Compare